<!-- HTML header for doxygen 1.8.6-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<title>OpenCV: Background Subtraction</title>
<link href="../../opencv.ico" rel="shortcut icon" type="image/x-icon" />
<link href="../../tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../jquery.js"></script>
<script type="text/javascript" src="../../dynsections.js"></script>
<script type="text/javascript" src="../../tutorial-utils.js"></script>
<link href="../../search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="../../search/searchdata.js"></script>
<script type="text/javascript" src="../../search/search.js"></script>
<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js", "TeX/AMSmath.js", "TeX/AMSsymbols.js"],
    jax: ["input/TeX","output/HTML-CSS"],
});
//<![CDATA[
MathJax.Hub.Config(
{
  TeX: {
      Macros: {
          matTT: [ "\\[ \\left|\\begin{array}{ccc} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{array}\\right| \\]", 9],
          fork: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ \\end{array} \\right.", 4],
          forkthree: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ \\end{array} \\right.", 6],
          forkfour: ["\\left\\{ \\begin{array}{l l} #1 & \\mbox{#2}\\\\ #3 & \\mbox{#4}\\\\ #5 & \\mbox{#6}\\\\ #7 & \\mbox{#8}\\\\ \\end{array} \\right.", 8],
          vecthree: ["\\begin{bmatrix} #1\\\\ #2\\\\ #3 \\end{bmatrix}", 3],
          vecthreethree: ["\\begin{bmatrix} #1 & #2 & #3\\\\ #4 & #5 & #6\\\\ #7 & #8 & #9 \\end{bmatrix}", 9],
          cameramatrix: ["#1 = \\begin{bmatrix} f_x & 0 & c_x\\\\ 0 & f_y & c_y\\\\ 0 & 0 & 1 \\end{bmatrix}", 1],
          distcoeffs: ["(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6 [, s_1, s_2, s_3, s_4[, \\tau_x, \\tau_y]]]]) \\text{ of 4, 5, 8, 12 or 14 elements}"],
          distcoeffsfisheye: ["(k_1, k_2, k_3, k_4)"],
          hdotsfor: ["\\dots", 1],
          mathbbm: ["\\mathbb{#1}", 1],
          bordermatrix: ["\\matrix{#1}", 1]
      }
  }
}
);
//]]>
</script><script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js"></script>
<link href="../../doxygen.css" rel="stylesheet" type="text/css" />
<link href="../../stylesheet.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<!--#include virtual="/google-search.html"-->
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectlogo"><img alt="Logo" src="../../opencv-logo-small.png"/></td>
  <td style="padding-left: 0.5em;">
   <div id="projectname">OpenCV
   &#160;<span id="projectnumber">4.5.2</span>
   </div>
   <div id="projectbrief">Open Source Computer Vision</div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "../../search",false,'Search');
</script>
<script type="text/javascript" src="../../menudata.js"></script>
<script type="text/javascript" src="../../menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('../../',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div id="nav-path" class="navpath">
  <ul>
<li class="navelem"><a class="el" href="../../d3/d81/tutorial_contrib_root.html">Tutorials for contrib modules</a></li><li class="navelem"><a class="el" href="../../d3/d89/tutorial_table_of_content_bgsegm.html">Tutorials for bgsegm module</a></li>  </ul>
</div>
</div><!-- top -->
<div class="header">
  <div class="headertitle">
<div class="title">Background Subtraction </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><h2>Goal </h2>
<p>In this chapter,</p>
<ul>
<li>We will familiarize with the background subtraction methods available in OpenCV.</li>
</ul>
<h2>Basics </h2>
<p>Background subtraction is a major preprocessing step in many vision-based applications. For example, consider the case of a visitor counter where a static camera takes the number of visitors entering or leaving the room, or a traffic camera extracting information about the vehicles etc. In all these cases, first you need to extract the person or vehicles alone. Technically, you need to extract the moving foreground from static background.</p>
<p>If you have an image of background alone, like an image of the room without visitors, image of the road without vehicles etc, it is an easy job. Just subtract the new image from the background. You get the foreground objects alone. But in most of the cases, you may not have such an image, so we need to extract the background from whatever images we have. It becomes more complicated when there are shadows of the vehicles. Since shadows also move, simple subtraction will mark that also as foreground. It complicates things.</p>
<p>Several algorithms were introduced for this purpose. In the following, we will have a look at two algorithms from the <code>bgsegm</code> module.</p>
<h3>BackgroundSubtractorMOG</h3>
<p>It is a Gaussian Mixture-based Background/Foreground Segmentation Algorithm. It was introduced in the paper "An improved adaptive background mixture model for real-time tracking with shadow
detection" by P. KadewTraKuPong and R. Bowden in 2001. It uses a method to model each background pixel by a mixture of K Gaussian distributions (K = 3 to 5). The weights of the mixture represent the time proportions that those colours stay in the scene. The probable background colours are the ones which stay longer and more static.</p>
<p>While coding, we need to create a background object using the function, <b><a class="el" href="../../d2/d55/group__bgsegm.html#ga17d9525d2ad71f74d8d29c2c5e11903d" title="Creates mixture-of-gaussian background subtractor. ">cv.bgsegm.createBackgroundSubtractorMOG()</a></b>. It has some optional parameters like length of history, number of gaussian mixtures, threshold etc. It is all set to some default values. Then inside the video loop, use backgroundsubtractor.apply() method to get the foreground mask.</p>
<p>See a simple example below: </p><div class="fragment"><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"></div><div class="line">cap = <a class="code" href="../../d8/dfe/classcv_1_1VideoCapture.html">cv.VideoCapture</a>(<span class="stringliteral">&#39;vtest.avi&#39;</span>)</div><div class="line"></div><div class="line">fgbg = <a class="code" href="../../d2/d55/group__bgsegm.html#ga17d9525d2ad71f74d8d29c2c5e11903d">cv.bgsegm.createBackgroundSubtractorMOG</a>()</div><div class="line"></div><div class="line">while(1):</div><div class="line">    ret, frame = cap.read()</div><div class="line"></div><div class="line">    fgmask = fgbg.apply(frame)</div><div class="line"></div><div class="line">    <a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;frame&#39;</span>,fgmask)</div><div class="line">    k = <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>(30) &amp; 0xff</div><div class="line">    <span class="keywordflow">if</span> k == 27:</div><div class="line">        <span class="keywordflow">break</span></div><div class="line"></div><div class="line">cap.release()</div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga6b7fc1c1a8960438156912027b38f481">cv.destroyAllWindows</a>()</div></div><!-- fragment --><p> ( All the results are shown at the end for comparison).</p>
<dl class="section note"><dt>Note</dt><dd>Documentation on the newer method <b><a class="el" href="../../de/de1/group__video__motion.html#ga2beb2dee7a073809ccec60f145b6b29c" title="Creates MOG2 Background Subtractor. ">cv.createBackgroundSubtractorMOG2()</a></b> can be found here: <a class="el" href="../../d1/dc5/tutorial_background_subtraction.html">How to Use Background Subtraction Methods</a></dd></dl>
<h3>BackgroundSubtractorGMG</h3>
<p>This algorithm combines statistical background image estimation and per-pixel Bayesian segmentation. It was introduced by Andrew B. Godbehere, Akihiro Matsukawa, and Ken Goldberg in their paper "Visual Tracking of Human Visitors under Variable-Lighting Conditions for a Responsive Audio Art Installation" in 2012. As per the paper, the system ran a successful interactive audio art installation called “Are We There Yet?” from March 31 - July 31 2011 at the Contemporary Jewish Museum in San Francisco, California.</p>
<p>It uses first few (120 by default) frames for background modelling. It employs probabilistic foreground segmentation algorithm that identifies possible foreground objects using Bayesian inference. The estimates are adaptive; newer observations are more heavily weighted than old observations to accommodate variable illumination. Several morphological filtering operations like closing and opening are done to remove unwanted noise. You will get a black window during first few frames.</p>
<p>It would be better to apply morphological opening to the result to remove the noises. </p><div class="fragment"><div class="line"><span class="keyword">import</span> numpy <span class="keyword">as</span> np</div><div class="line"><span class="keyword">import</span> cv2 <span class="keyword">as</span> cv</div><div class="line"></div><div class="line">cap = <a class="code" href="../../d8/dfe/classcv_1_1VideoCapture.html">cv.VideoCapture</a>(<span class="stringliteral">&#39;vtest.avi&#39;</span>)</div><div class="line"></div><div class="line">kernel = <a class="code" href="../../d4/d86/group__imgproc__filter.html#gac342a1bb6eabf6f55c803b09268e36dc">cv.getStructuringElement</a>(cv.MORPH_ELLIPSE,(3,3))</div><div class="line">fgbg = <a class="code" href="../../d2/d55/group__bgsegm.html#gae561c9701970d0e6b35ec12bae149814">cv.bgsegm.createBackgroundSubtractorGMG</a>()</div><div class="line"></div><div class="line">while(1):</div><div class="line">    ret, frame = cap.read()</div><div class="line"></div><div class="line">    fgmask = fgbg.apply(frame)</div><div class="line">    fgmask = <a class="code" href="../../d4/d86/group__imgproc__filter.html#ga67493776e3ad1a3df63883829375201f">cv.morphologyEx</a>(fgmask, cv.MORPH_OPEN, kernel)</div><div class="line"></div><div class="line">    <a class="code" href="../../df/d24/group__highgui__opengl.html#gaae7e90aa3415c68dba22a5ff2cefc25d">cv.imshow</a>(<span class="stringliteral">&#39;frame&#39;</span>,fgmask)</div><div class="line">    k = <a class="code" href="../../d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7">cv.waitKey</a>(30) &amp; 0xff</div><div class="line">    <span class="keywordflow">if</span> k == 27:</div><div class="line">        <span class="keywordflow">break</span></div><div class="line"></div><div class="line">cap.release()</div><div class="line"><a class="code" href="../../d7/dfc/group__highgui.html#ga6b7fc1c1a8960438156912027b38f481">cv.destroyAllWindows</a>()</div></div><!-- fragment --> <h2>Results </h2>
<p><b>Original Frame</b></p>
<p>Below image shows the 200th frame of a video</p>
<div class="image">
<img src="../../resframe.jpg" alt="resframe.jpg"/>
<div class="caption">
image</div></div>
<p> <b>Result of BackgroundSubtractorMOG</b></p>
<div class="image">
<img src="../../resmog.jpg" alt="resmog.jpg"/>
<div class="caption">
image</div></div>
<p> <b>Result of BackgroundSubtractorGMG</b></p>
<p>Noise is removed with morphological opening.</p>
<div class="image">
<img src="../../resgmg.jpg" alt="resgmg.jpg"/>
<div class="caption">
image</div></div>
 <h2>Additional Resources </h2>
<h2>Exercises </h2>
</div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.6-->
<!-- start footer part -->
<hr class="footer"/><address class="footer"><small>
Generated on Fri Apr 2 2021 11:36:38 for OpenCV by &#160;<a href="http://www.doxygen.org/index.html">
<img class="footer" src="../../doxygen.png" alt="doxygen"/>
</a> 1.8.13
</small></address>
<script type="text/javascript">
//<![CDATA[
addTutorialsButtons();
//]]>
</script>
</body>
</html>
